﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LX.Cache;
using LX.Core.Auth;
using LX.Core.Data;
using LX.Core.Log;
using LX.Data;
using LX.Exceptions;
using LX.IO;
using LX.Log;

namespace LX.Data
{
    /// <summary>
    /// 应用服务上下文
    /// </summary>
    public class ApplicationServiceContext : IApplicationServiceContext
    {
        private IPersistentProvider _persistentProvider=new EmptyPersistentProvider();
        private ILog _logger=new EmptyLog();
        private IAuthorizeManager _authorizeManager=new EmptyAuthorizeManager();
        private IPrincipal _currentPrincipal = Principal.Anonymous;
        private string _actionname = "";

        /// <summary>
        /// 持久化容器
        /// </summary>
        public IPersistentProvider PersistentProvider
        {
            get { return _persistentProvider; }
            set { _persistentProvider = value; }
        }

        /// <summary>
        /// 日志记录器
        /// </summary>
        public ILog Logger
        {
            get { return _logger; }
            set { _logger = value; }
        }

        /// <summary>
        /// 授权管理器
        /// </summary>
        public IAuthorizeManager AuthorizeManager
        {
            get { return _authorizeManager; }
            set { _authorizeManager = value; }
        }

        /// <summary>
        /// 当前安全主体
        /// </summary>
        public IPrincipal CurrentPrincipal
        {
            get { return _currentPrincipal; }
            set { _currentPrincipal = value; }
        }

        /// <summary>
        /// 文件管理器
        /// </summary>
        public IDistributionFileManager FileManager { get; set; }

        /// <summary>
        /// 缓存管理器
        /// </summary>
        public ICacheProvider CacheProvider { get; set; }

        /// <summary>
        /// 设置操作名称
        /// </summary>
        /// <param name="name"></param>
        public IApplicationServiceContext Named(string name)
        {
            _actionname = name;
            return this;
        }

        private bool needauth = false;

        public void Do(Action<ApplicationTransaction> fun)
        {
            Check();
            if (!string.IsNullOrWhiteSpace(_actionname)) _logger.Write(CurrentPrincipal.GetId() + " BeginRun: " + _actionname, EventLevel.Audit);
            try
            {
                using (var trans = new ApplicationTransaction
                                      {
                                          Repository = PersistentProvider.GetPersistentContext(),
                                          AuthorizeManager = this.AuthorizeManager,
                                          CurrentPrincipal = this.CurrentPrincipal,
                                          FileManager = FileManager,
                                          Logger = Logger,
                                          CacheProvider=CacheProvider
                                      })
                {
                    fun(trans);
                }
            }
            catch(Exception e)
            {
                _logger.Write(CurrentPrincipal.GetId() + " ErrorOn: " + _actionname+" ==>"+e.ToString(), EventLevel.Error);
                throw;
            }
        }

        public T Do<T>(Func<ApplicationTransaction, T> fun)
        {
            Check();
            _logger.Write(CurrentPrincipal.GetId() + " BeginRun: " + _actionname, EventLevel.Audit);
            try
            {
                using (var trans = new ApplicationTransaction
                {
                    Repository = PersistentProvider.GetPersistentContext(),
                    AuthorizeManager = this.AuthorizeManager,
                    CurrentPrincipal = this.CurrentPrincipal,
                    FileManager = FileManager,
                    Logger = Logger,
                    CacheProvider = CacheProvider
                })
                {
                    return fun(trans);
                }
            }
            catch
            {
                _logger.Write(CurrentPrincipal.GetId() + " ErrorOn: " + _actionname, EventLevel.Error);
                throw;
            }
        }

        private void Check()
        {
            if (!needauth) return;
            if (string.IsNullOrWhiteSpace(_actionname)) return;
            if(!AuthorizeManager.CanOperate(CurrentPrincipal, _actionname))
            {
                _logger.Write(CurrentPrincipal.GetId() + " NoPower: " + _actionname, EventLevel.Audit);
                throw new NopowerException();
            }
        }

        public IApplicationServiceContext RunIn(System.Reflection.MethodBase methodinfo)
        {
            var attributes = methodinfo.GetCustomAttributes(true);
            foreach (var att in attributes)
            {
                if(att is AuthAttribute)
                {
                    var authatt = att as AuthAttribute;
                    needauth = authatt.NeedCheck;
                    continue;
                }
                if(att is OperationAttribute)
                {
                    var opatt = att as OperationAttribute;
                    _actionname = opatt.Name;
                }
            }
            return this;
        }
    }
}
